<?php
class tvapi_default
{
    const BASE_URL = 'http://www.thetvdb.com/api/';
    const SERIA = 1;
    const EPISODES = 2;
    const ACTORS = 4;
    const BANNERS = 8;

    private $key;
    private $previousTime;
    private $language;

    protected $allMirrors;
    protected $mirrors;

    protected $masks;
    protected $fieldFilters;

    public function __construct($apiKey, $language = 'en', $initialTime = 0)
    {
        $this->key = $apiKey;
        $this->setLanguage($language);
        $this->previousTime = $initialTime != 0 ? $initialTime : time();

        $this->mirrors =
        $this->allMirrors = array();
        $this->masks = array('xml' => 1, 'banner' => 2, 'zip' => 4);

        $this->fieldFilters = array(
            'seria' => array(
    			'id', 'language', 'seriesname', 'banner', 'overview', 'firstaired', 'imdb_id',
    			'actors', 'airs_dayofweek', 'airs_time', 'genre', 'network', 'networkid',
    			'rating', 'runtime', 'status'
    		),
    		'episode' => array(
    		    'id', 'combined_episodenumber', 'combined_season', 'director', 'episodename',
    		    'episodenumber', 'firstaired', 'gueststars', 'language', 'overview', 'rating',
    		    'seasonnumber', 'writer', 'absolute_number', 'filename', 'seasonid', 'seriesid'
    		),
    		'hit' => array(
    		    'id', 'seriesname', 'firstaired', 'checked'
    		)
        );
    }

    public function setLanguage($lang)
    {
        $this->language = strtolower($lang);
        return $this;
    }

    public function getLanguage()
    {
        return $this->language;
    }

    public function loadMirrors($andPick = true)
    {
        $url = self::BASE_URL . $this->key . '/mirrors.xml';
        $xml = simplexml_load_file($url);
        if ($xml === false) {
            throw new Exception('Nem sikerült elérni a mirrorokat tartalmazó XML-t.', 404);
        }

        if (!isset($xml->Mirror)) {
            throw new Exception('Nem található egy mirror sem!');
        }

        $mirrors = array(
            'xml' => array(),
            'banner' => array(),
            'zip'	=> array()
        );

        foreach ($xml->Mirror as $data) {
            //$id = (int)$data->id;
            $path = (string)$data->mirrorpath;
            $mask = (int)$data->typemask;

            foreach ($this->masks as $type => $val) {
                if ( ($mask | $val) == $mask) {
                    $mirrors[$type][] = $path;
                }
            }
        }
        $this->allMirrors = $mirrors;

        if ($andPick) {
            $this->pickMirror($mirrors);
        }

        return $mirrors;
    }

    public function pickMirror(array $mirrors, $type = 'all')
    {
        $types = array('xml', 'banner', 'zip');

        if ($type == 'all') {
            foreach ($types as $nextType) {
                $this->pickMirror($mirrors, $nextType);
            }
            return;
        }

        if (!in_array($type, $types)) {
            throw new Exception('Invalid mirror type: ' . $type);
        }

        if (empty($mirrors[$type])) {
            throw new MirrorException('Nincs mirror a kategóriában: ' . $type);
        }

        $random = mt_rand(0, count($mirrors[$type]) - 1);
        $this->mirrors[$type] = $mirrors[$type][$random];
    }

    public function getMirror($type = '')
    {
        if (empty($this->mirrors)) {
            $this->loadMirrors();
        }
        return isset($this->mirrors[$type]) ? $this->mirrors[$type] : $this->mirrors;
    }

    public function loadServerTime()
    {
        $xml = simplexml_load_file(self::BASE_URL . 'Updates.php?type=none');
        if ($xml === false) {
            throw new Exception('Nem sikerült lekérdezni a szerver idejét tartalmazó XML-t.', 404);
        }

        if (!isset($xml->Time)) {
            throw new Exception('Nem sikerült lekérni a szerveridőt');
        }

        $this->previousTime = (int)$xml->Time;
        return $this->previousTime;
    }

    public function getPreviousTime()
    {
        return $this->previousTime;
    }

    public function setPreviousTime($time)
    {
        $this->previousTime = $time;
        return $this;
    }

    public function searchSeria($name, $fieldFilter = array())
    {
        $url = self::BASE_URL . 'GetSeries.php?seriesname=' . urlencode($name) . '*&language=' . $this->language;
		$xml = @simplexml_load_file($url);
		if ($xml === false) {
		    throw new Exception('Nem sikerült lekérdezni a sorozat adatait tartalmazó XML-t.', 404);
		}

		if (!isset($xml->Series)) {
		    throw new Exception('Nem található ilyen sorozat: ' . $name, 404);
		}

		if (empty($fieldFilter)) {
		    $fieldFilter = $this->fieldFilters['seria'];
		}

		return $this->xmlFieldFilter($xml->Series, $fieldFilter);
    }

    public function loadSeriaAllData($seria_id, $mask = 3)
    {
        $url = sprintf('%s/api/%s/series/%d/all/%s.zip',
                        $this->getMirror('zip'), $this->key, $seria_id, $this->language);

        $return = array();
        getURLContent($url, './temp/temp.zip');
		$zip = new ZipArchive;
		if ($zip->open('./temp/temp.zip') === true) {
		    if ( ($mask & self::SERIA) || ($mask & self::EPISODES) ) {
		        $content = $zip->getFromName($this->language . '.xml');
		        $dataXML = simplexml_load_string($content);
		        if ($mask & self::SERIA) {
		            $seriaData = $this->xmlFieldFilter($dataXML->Series, $this->getFieldFilter('seria'));
		            $return['seria'] = isset($seriaData[0]) ? $seriaData[0] : array();
		        }
		        if ($mask & self::EPISODES) {
		            $return['episodes'] =  $this->xmlFieldFilter($dataXML->Episode, $this->getFieldFilter('episode'));
		        }
		    }
		    if ($mask & self::ACTORS) {
		        $actors = $zip->getFromName('actors.xml');
		        $actorXML  = simplexml_load_string($actors);
		        $return['actors']  = $this->xmlFieldFilter($actorXML, array());
		    }
		    if ($mask & self::BANNERS) {
    			$banners = $zip->getFromName('banners.xml');
    			$bannerXML = simplexml_load_string($banners);
    			$return['banners'] = $this->xmlFieldFilter($bannerXML, array());
		    }
		    $zip->close();
		} else {
		    throw new Exception('Hiba a sorozat (id: '.$seria_id.') zip fájlának megnyitásánál.', 404);
		}

		return $return;
    }

    public function loadUpdatesList($time = 0)
    {
        if ($time == 0)
        {
            $time = $this->previousTime;
        }

        $url = self::BASE_URL . 'Updates.php?type=all&time=' . $time;
        $xml = simplexml_load_file($url);
        if ($xml === false) {
            throw new Exception('Nem sikerült lekérni a frissítések listáját tartalmazó XML-t.', 404);
        }

        $serverTime = (int)$xml->Time;

        $series = array();
        foreach ($xml->Series as $seria) {
            $series[] = (int)$seria;
        }

        $episodes = array();
        foreach ($xml->Episode as $episode) {
            $episodes[] = (int)$episode;
        }

        return array(
            'servertime' => $serverTime,
            'series' => $series,
            'episodes' => $episodes
        );
    }

    public function loadData($id, $type = 'seria')
    {
        try {
            $type = $this->typeFilter($type);
        } catch (Exception $e) {
            _pr($e->getMessage());
        }

        $xml = simplexml_load_file($this->getLink($id, $type));
        if ($xml === false) {
            throw new Exception('Nem sikerült lekérdezni a ' . $type . ' adatait tartalmazó XML-t.', 404);
        }

        $data = $this->xmlFieldFilter($xml, $this->fieldFilters[$type]);
        return $data[0];
    }

    public function getLink($id, $type = 'series')
    {
        try {
            $type = $this->typeFilter($type, 'series', 'episodes');
        } catch (Exception $e) {
            _pr($e->getMessage());
        }

        return sprintf('%s/api/%s/%s/%d/%s.xml',
                        $this->getMirror('xml'), $this->key, $type,
                        $id, $this->language);
    }

    public function xmlFieldFilter($xmldata, array $filterAry)
    {
        $i = 0;
        $needed = array();
        foreach ($xmldata as $root) {
            $root = $this->arrayLowerKeys($root);
            $needed[$i] = array();

            if (empty($filterAry)) {
                $needed[$i] = $root;
            } else {
                foreach ($filterAry as $prop) {
                    if (isset($root[$prop])) {
                        $needed[$i][$prop] = (string)$root[$prop];
                    }
                }
            }
            $i++;
        }
        return $needed;
    }

    protected function arrayLowerKeys($ary)
    {
        if (!is_array($ary)) {
            $ary = (array)$ary;
        }

        $lowered = array();
        foreach ($ary as $key => $val) {
            $lowered[strtolower($key)] = $val;
        }
        return $lowered;
    }

    public function getFieldFilter($type)
    {
        try {
            $type = $this->typeFilter($type);
        } catch (Exception $e) {
            _pr($e->getMessage());
        }

        if (isset($this->fieldFilters[$type])) {
            return $this->fieldFilters[$type];
        }
        return array();
    }

    protected function typeFilter($type, $seria = 'seria', $episode = 'episode')
    {
        $types = array(
            's' => array('seria', 'serie', 'series', 'se', 'serias'),
            'e' => array('episode', 'episodes', 'ep')
        );

        if (in_array($type, $types['s'])) {
            $return = $seria;
        } elseif(in_array($type, $types['e'])) {
            $return = $episode;
        } else {
            throw new Exception('Hibás típus.', 403);
        }

        return $return;
    }
}
class MirrorException extends Exception {}